package org.kalai.unifypay.chanpay;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.kalai.unifypay.Constant;
import org.kalai.unifypay.bean.Transflow;
import org.kalai.unifypay.chanpay.CjSignHelper.VerifyResult;
import org.kalai.unifypay.util.CommonUtil;
import org.kalai.unifypay.util.DataDao;
import org.kalai.unifypay.util.DateUtil;
import org.kalai.unifypay.util.HttpUtil;
import org.kalai.unifypay.util.PropertiesUtil;
import org.kalai.unifypay.util.StringUtil;

import com.lechinepay.channel.chanpay.gateway.Gateway;
import com.lechinepay.channel.chanpay.gateway.request.QuickPaymentConfirmRequest;
import com.lechinepay.channel.chanpay.gateway.request.QuickPaymentRequest;
import com.lechinepay.channel.chanpay.gateway.response.QuickPaymentConfirmResponse;
import com.lechinepay.channel.chanpay.gateway.response.QuickPaymentResponse;
import com.sun.corba.se.spi.orbutil.fsm.Guard.Result;

/**
 * 
 * @author Renne66 https://cop-gateway.chanpay.com/crps-gateway/gw01/process01
 *         40363101 00000000
 */
public final class Chanpay {

   private static final Logger logger               = Logger.getLogger(Chanpay.class);

   /**
    * 平台公钥
    */
   private static String       MERCHANT_PUBLIC_KEY  = PropertiesUtil.getProperties("CJ_MERCHANT_PUBLIC_KEY");

   /**
    * 商户私钥
    */
   private static String       MERCHANT_PRIVATE_KEY = PropertiesUtil.getProperties("CJ_MERCHANT_PRIVATE_KEY");

   /**
    * 请求地址
    */
   private static String       GATEWAY_URL          = PropertiesUtil.getProperties("CJ_GATEWAY_URL");

   /**
    * 异步回调地址
    */
   private static String       CJ_NOTIFY_URL        = PropertiesUtil.getProperties("CJ_NOTIFY_URL");

   /**
    * 畅捷代付接口
    * 
    * @param bankGeneralName
    *           银行名称
    * @param accountNo
    *           账号
    * @param accountName
    *           姓名
    * @param province
    *           省份
    * @param city
    *           城市
    * @param amount
    *           金额（分）
    * @return
    */
   public final static Map<String, String> pay(String tranxSN, String bankGeneralName, String accountNo, String accountName,
         long amount) {
      ChangJMessage cjm = new ChangJMessage();
      cjm.setReqSn(tranxSN);
      cjm.setMertid("cp2016080403631");// 生产企业编码
      cjm.setBusinessCode("09900");// 代付业务类型编码
      cjm.setCorpAccNo("698058643");// 企业账号
      cjm.setProductCode("60020002");// 产品码
      cjm.setAccountProp("0");// 0-对私 1-对公
      cjm.setBankGeneralName(bankGeneralName);// 银行通用名称
      cjm.setAccountType("00");// 00=银行卡，01=存折，02=信用卡。不填默认为银行卡00。
      cjm.setAccountNo(accountNo);// 银行卡或存折号码
      cjm.setAccountName(accountName);// 银行卡或存折上的所有人姓名。
      // cjm.setProvince(province);//开户行所在省
      // cjm.setCity(city);//开户行所在市
      // cjm.setBankName(bankName);//开户行名称
      // cjm.setBankCode(bankCode);//开户行号
      // cjm.setDrctBankCode("710584000001");//清算行号
      cjm.setCurrency("CNY");// 人民币：CNY, 港元：HKD，美元：USD。不填时，默认为人民币。
      cjm.setAmount(amount);// 金额 单位：分
      // cjm.setIdType("0");
      // cjm.setId("420624199209212219");
      // cjm.setTel("17097221966");
      // cjm.setCorpFlowNo("9876541230");
      // cjm.setSummary("测试DEMO");
      // cjm.setPostscript("测试DEMO");
      String xml = buildMsg(cjm);
      String signxml = new CjSignHelper().signXml$Add(xml);
      logger.info("发送畅捷代付交易请求：" + tranxSN);
      String ret = HttpUtil.sendHttpsPost(Constant.CHANPAY_URL, signxml);
      // 验证签名
      VerifyResult verifyResult = new CjSignHelper().verifyCjServerXml(ret);
      if (!verifyResult.result) {
         logger.error("验证CJ返回数据的签名失败！" + verifyResult.errMsg);
      }
      parseCjMsgToDto(ret, cjm);
      if ("0000".equals(cjm.getRetCode())) {
         Map<String, String> map = new HashMap<>();
         map.put("respCode", cjm.getRetCode());
         map.put("respDesc", cjm.getErrMsg());
         logger.info("接收畅捷代付交易请求：" + tranxSN + "-" + map);
         return map;
      } else {
         logger.info("畅捷代付失败：" + xml);
         logger.info("畅捷代付失败响应信息：" + cjm.toString());
         return null;
      }
   }

   private static String buildMsg(ChangJMessage message) {
      Document doc = DocumentHelper.createDocument();
      Element msgEl = doc.addElement("MESSAGE");

      Element infoEl = msgEl.addElement("INFO");
      infoEl.addElement("TRX_CODE").setText("G10002");
      infoEl.addElement("VERSION").setText("01");
      infoEl.addElement("MERCHANT_ID").setText(isBlankReplace(message.getMertid()));
      infoEl.addElement("REQ_SN").setText(isBlankReplace(message.getReqSn()));
      infoEl.addElement("TIMESTAMP").setText(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
      infoEl.addElement("SIGNED_MSG").setText("");

      Element bodyEl = msgEl.addElement("BODY");
      bodyEl.addElement("BUSINESS_CODE").setText(isBlankReplace(message.getBusinessCode()));
      bodyEl.addElement("CORP_ACCT_NO").setText(isBlankReplace(message.getCorpAccNo()));
      bodyEl.addElement("PRODUCT_CODE").setText(isBlankReplace(message.getProductCode()));
      bodyEl.addElement("ACCOUNT_PROP").setText(isBlankReplace(message.getAccountProp()));
      bodyEl.addElement("SUB_MERCHANT_ID").setText(isBlankReplace(message.getSubMertid()));
      bodyEl.addElement("BANK_GENERAL_NAME").setText(isBlankReplace(message.getBankGeneralName()));
      bodyEl.addElement("ACCOUNT_TYPE").setText(isBlankReplace(message.getAccountType()));
      bodyEl.addElement("ACCOUNT_NO").setText(isBlankReplace(message.getAccountNo()));
      bodyEl.addElement("ACCOUNT_NAME").setText(isBlankReplace(message.getAccountName()));
      bodyEl.addElement("PROVINCE").setText(isBlankReplace(message.getProvince()));
      bodyEl.addElement("CITY").setText(isBlankReplace(message.getCity()));
      bodyEl.addElement("BANK_NAME").setText(isBlankReplace(message.getBankName()));
      bodyEl.addElement("BANK_CODE").setText(isBlankReplace(message.getBankCode()));
      bodyEl.addElement("DRCT_BANK_CODE").setText(isBlankReplace(message.getDrctBankCode()));
      bodyEl.addElement("PROTOCOL_NO").setText(isBlankReplace(message.getProtocolNo()));
      bodyEl.addElement("CURRENCY").setText(isBlankReplace(message.getCurrency()));
      bodyEl.addElement("AMOUNT").setText(((Long) message.getAmount()) == null ? "" : message.getAmount() + "");
      bodyEl.addElement("ID_TYPE").setText(isBlankReplace(message.getIdType()));
      bodyEl.addElement("ID").setText(isBlankReplace(message.getId()));
      bodyEl.addElement("TEL").setText(isBlankReplace(message.getTel()));
      bodyEl.addElement("CORP_FLOW_NO").setText(isBlankReplace(message.getCorpFlowNo()));
      bodyEl.addElement("SUMMARY").setText(isBlankReplace(message.getSummary()));
      bodyEl.addElement("POSTSCRIPT").setText(isBlankReplace(message.getPostscript()));
      return StringUtil.xmlToStr(doc);
   }

   private static String isBlankReplace(String str) {
      return StringUtils.isBlank(str) ? "" : str.trim();
   }

   private static void parseCjMsgToDto(String cjRespmsg, ChangJMessage data) {
      try {
         Document reqDoc = DocumentHelper.parseText(cjRespmsg);
         Element msgEl = reqDoc.getRootElement();
         Element infoEl = msgEl.element("INFO");
         data.setRetCode(infoEl.elementText("RET_CODE"));
         data.setErrMsg(infoEl.elementText("ERR_MSG"));
         data.setTimestamp(infoEl.elementText("TIMESTAMP"));
      } catch (DocumentException e) {
         logger.error(e.getMessage(), e);
      }
   }// method

   /**
    * 快捷支付创建订单(并发送短信)
    */
   public static Map<String, Object> quickPayment(String tranxSN, double transAmt, String subject, String ID_Name,
         String ID_Card, String phone, String acctNo, String cvn2, String expDate, String cardType, String shortCode) {

      Map<String, Object> respMap = CommonUtil.createRespMap("XXXX", "验签失败");
      QuickPaymentResponse result=new QuickPaymentResponse();
      try {
         QuickPaymentRequest baseRequest = new QuickPaymentRequest();

         baseRequest.setTrade_amount(String.valueOf(transAmt));
         baseRequest.setProduct_name(subject);
         baseRequest.setNotify_url(CJ_NOTIFY_URL);
         baseRequest.setOrder_time(DateUtil.formatNow("yyyyMMddHHmmss"));
         baseRequest.setOut_trade_no(tranxSN);
         baseRequest.setBuyer_ip("101.67.157.22");
         /* 支付相关参数 */
         baseRequest.setCard_type(cardType); // 借记：DC；贷记：CC
         baseRequest.setPay_type("C");// 对公：B；对私：C
         baseRequest.setBank_code(shortCode);
         baseRequest.setPayer_name(ID_Name);
         baseRequest.setId_number(ID_Card);
         baseRequest.setPayer_card_no(acctNo);
         baseRequest.setPhone_number(phone);
         /* 借记卡可不需要此参数 */
         if (StringUtil.isNotEmpty(expDate, cvn2)) {
            baseRequest.setExpiry_date(expDate);
            baseRequest.setCvv2(cvn2);
         }
          result = Gateway.doQuickPaymentRequest(baseRequest, GATEWAY_URL, MERCHANT_PRIVATE_KEY,
               MERCHANT_PUBLIC_KEY);
         if (result.getAuthenticate_status().equals("0")) {
            respMap = CommonUtil.createRespMap("00", "订单创建成功");
         } else {
            respMap = CommonUtil.createRespMap(result.getAuthenticate_status(), result.getErr_msg());
            logger.error("baseRequest.toMap()=" + baseRequest.toMap());
         }
      } catch (Exception e) {
         logger.error(String.format("畅捷快捷创建订单异常:[tranxSN=%s][result=%s]%s", tranxSN,result.toMap(), e));
         return respMap = CommonUtil.createRespMap("10", "快捷创建订单失败,系统异常");
      }
      return respMap;
   }

   /**
    * 快捷支付(确认)
    */
   public static Map<String, Object> quickPaymentConfirm(String tranxSN, String verificationCode) {
      Map<String, Object> respMap = CommonUtil.createRespMap("XXXX", "验签失败");
      try {
         QuickPaymentConfirmRequest baseRequest = new QuickPaymentConfirmRequest();

         baseRequest.setOut_trade_no(tranxSN);
         baseRequest.setVerification_code(verificationCode);

         // 查询订单信息
         Transflow transflow = DataDao.getInstance().getTransflow(tranxSN);
         if (transflow == null)
            throw new RuntimeException("订单查询为空");

         QuickPaymentConfirmResponse result = Gateway
               .doQuickPaymentConfirmRequest(baseRequest, GATEWAY_URL, MERCHANT_PRIVATE_KEY);
         if ("0".equals(result.getTrade_status())) {
            respMap = CommonUtil.createRespMap("00", "支付成功");
            DataDao.getInstance().updateTransflow(transflow.getTranxSN(), "", 0, 1, "0", "同步支付成功");
         } else if ("1".equals(result.getTrade_status())) {
            respMap = CommonUtil.createRespMap("01", "支付处理中");
         } else {
            respMap = CommonUtil.createRespMap("02", "支付失败");
            logger.error(String.format("畅捷快捷支付同步失败:[result=%s]", result.toMap()));
         }
      } catch (Exception e) {
         logger.error(String.format("畅捷快捷支付异常:[tranxSN=%s]%s", tranxSN, e));
         return respMap = CommonUtil.createRespMap("10", "快捷支付失败,系统异常");
      }
      return respMap;
   }

   public static void main(String[] args) {
      // System.out.println(pay("STG10011709722196608221111190289", "中国工商银行",
      // "6217231202001760765", "曾庆达", 200));
   }
}
